
package com.be.beadmin.logging.impl;

import cn.hutool.json.JSONUtil;
import com.alibaba.druid.util.StringUtils;
import com.be.beadmin.logging.entity.Log;
import cn.hutool.core.util.ObjectUtil;
import com.be.beadmin.common.entity.PageEntity;
import com.be.beadmin.common.exception.BeadminException;
import com.be.beadmin.common.utils.JpaQueryBuilder;
import com.be.beadmin.common.utils.JpaSortBuilder;
import com.be.beadmin.logging.entity.Log_;
import lombok.RequiredArgsConstructor;
import com.be.beadmin.logging.mapper.LogMapperEx;
import com.be.beadmin.logging.repository.LogRepository;
import com.be.beadmin.logging.service.LogService;
import com.be.beadmin.logging.dto.input.LogDto;
import com.be.beadmin.logging.dto.output.LogEx;
import com.be.beadmin.logging.dto.input.LogQueryCriteria;
import com.be.beadmin.logging.mapper.LogMapper;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;

import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Order;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.*;

/**
* @description 服务实现
* @author chenwei
* @date 2022-12-27
**/
@Service
@RequiredArgsConstructor
public class LogServiceImpl implements LogService {

    @Autowired
    private  LogRepository logRepository;
    @Autowired
    private  LogMapper logMapper;
    @Autowired
    private  LogMapperEx logExMapper;

    @Override
    public Page<LogEx> getLogByPage(PageEntity pageEntity) {
            Pageable pageable = PageRequest.of(
            pageEntity.getCurrent() -1,
            pageEntity.getPageSize());
            Page<Log> page = logRepository.findAll((root, criteriaQuery, criteriaBuilder) -> {
                    List<Predicate> list = new ArrayList<>();
                    Predicate pre1 =   JpaQueryBuilder.getPredicate(root, pageEntity.getFilters(), criteriaBuilder);
                    list.add(pre1);
                    Predicate pre2 = criteriaBuilder.equal(root.get(Log_.delete), 0); //过滤为0
                    list.add(pre2);
                    Predicate[] p = new Predicate[list.size()];
                    List<Order> orders = new ArrayList<>();
                    if(pageEntity.getSorters() != null && pageEntity.getSorters().size() > 0) {
                        orders = JpaSortBuilder.getPredicate(root, pageEntity.getSorters(), criteriaBuilder);
                        criteriaQuery.orderBy(orders);
                    } else {
                        criteriaQuery.orderBy(criteriaBuilder.desc(root.get(Log_.createTime).as(Date.class)));
                    }
                    return  criteriaBuilder.and(list.toArray(p));
                    }
                    , pageable);
            Page<LogEx> page1 = page.map(logExMapper::toEntity);
            return page1;

    }

    @Override
    public void addLog(LogDto logDto) {
            Log result = logRepository.findLogByIdAndDelete(logDto.getId(), 0);
            if(ObjectUtil.isNotEmpty(result)) {
                throw new BeadminException("Log不存在,请重新查询");
            }
            Log log = logMapper.toEntity(logDto);
            logRepository.save(log);
    }

    @Override
    public void updateLog(LogDto logDto) {
            Log log = logRepository.findLogById(logDto.getId());
            log = logMapper.toEntity(logDto);
            logRepository.save(log);
    }


    @Override
    public void delLog(String id) {
        Log log = logRepository.findLogById(id);
        log.setDelete(1);
        logRepository.save(log);
    }

    @Override
    public void delLogs (List<String> ids) { }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void save(String username, String browser, String ip, ProceedingJoinPoint joinPoint, Log log) {
        if (log == null) {
            throw new IllegalArgumentException("log 不能为null");
        }
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();

        Method method = signature.getMethod();

        com.be.beadmin.logging.annotation.Log aopLog =   method.getAnnotation(com.be.beadmin.logging.annotation.Log.class);

        // 方法路径
        String methodName = joinPoint.getTarget().getClass().getName() + "." + signature.getName() + "()";
        // 描述
        log.setDescription(aopLog.value());

        log.setRequestIp(ip);
//        log.setAddress(StringUtils.getCityInfo(log.getRequestIp()));
        log.setMethod(methodName);
        log.setUsername(username);
        log.setParams(getParameter(method, joinPoint.getArgs()));
        // 记住登录用户,影藏密码信息
        logRepository.save(log);



    }

    private String getParameter(Method method, Object[] args) {
        List<Object> argList = new ArrayList<>();
        Parameter[] parameters = method.getParameters();
        for (int i = 0; i < parameters.length; i++) {
            //将RequestBody注解修饰的参数作为请求参数
            RequestBody requestBody = parameters[i].getAnnotation(RequestBody.class);
            if (requestBody != null) {
                argList.add(args[i]);
            }
            //将RequestParam注解修饰的参数作为请求参数
            RequestParam requestParam = parameters[i].getAnnotation(RequestParam.class);
            if (requestParam != null) {
                Map<String, Object> map = new HashMap<>(4);
                String key = parameters[i].getName();
                if (!StringUtils.isEmpty(requestParam.value())) {
                    key = requestParam.value();
                }
                map.put(key, args[i]);
                argList.add(map);
            }
        }
        if (argList.isEmpty()) {
            return "";
        }
        return argList.size() == 1 ? JSONUtil.toJsonStr(argList.get(0)) : JSONUtil.toJsonStr(argList);
    }
}